#ifndef __GRPC_ASYNC_H__
#define __GRPC_ASYNC_H__

#include <string>
#include <boost/shared_ptr.hpp>
#include <boost/thread.hpp>
#include <grpc/grpc.h>
#include <grpcpp/server.h>
#include <grpcpp/server_builder.h>
#include <grpcpp/server_context.h>
#include <grpcpp/security/server_credentials.h>

template<typename TService>
class GrpcAsync{
public:
    typedef std::shared_ptr<grpc::ServerCompletionQueue> ServerCompletionQueuePtr;
    typedef boost::shared_ptr<grpc::Server> ServerPtr;
    typedef boost::shared_ptr<TService> TServicePtr;

    virtual void setListen(const std::string& address){
        m_Address = address;
    };

    virtual bool start(){
        m_pService = TServicePtr(new TServicePtr::element_type());

		grpc::ServerBuilder builder;
		builder.AddListeningPort(m_Address, grpc::InsecureServerCredentials());
		builder.RegisterService(&m_pService->getService());
		m_pQueue = builder.AddCompletionQueue();
		m_pServer = builder.BuildAndStart();
        m_thread = boost::bind();
        return m_pQueue && m_pServer && addService();
    };

    virtual void stop(){
        if(m_pServer){
            m_pServer->Shutdown();
            m_pServer.reset();
        }
        if(m_pQueue){
            m_pQueue->Shutdown();
            m_pQueue.reset();
        }
        if(m_pService){
            m_pService->stop();
            m_pService.reset();
        }
    };

    virtual bool addService(){
        return m_pService->addListen(m_pService);
    };
protected:
    static void handleTHread(ServerCompletionQueuePtr pQueue, TServicePtr pService){
        try{
            void* tag = nullptr;
            bool ok = false;
            while(true){
                tag = nullptr;
                ok = false;
                pQueue->Next(&tag, &ok);
                if(!ok){
                    std::cerr<<"queue next error"<<std::endl;
                }else{
                    pService->notify(tag);
                }
            }
        }catch(std::exception& e){
            std::cerr<<"queue error:"<<e.what()<<std::endl;
        }
    };

    std::string m_Address;
    ServerCompletionQueuePtr m_pQueue;
    ServerPtr m_pServer;
    TServicePtr m_pService;
    boost::thread m_thread;
};






#endif